package com.treasure.mall.biz.service.core.pay.impl;

import com.treasure.mall.biz.bo.config.BasicsConfig;
import com.treasure.mall.biz.dto.order.BizOrderCreateDTO;
import com.treasure.mall.biz.dto.pay.PayDTO;
import com.treasure.mall.biz.dto.pay.PaymentBillSaveDTO;
import com.treasure.mall.biz.dto.user.ModifyBalanceDTO;
import com.treasure.mall.biz.entity.order.BizOrderPO;
import com.treasure.mall.biz.entity.order.DealOrderPO;
import com.treasure.mall.biz.entity.order.OrderItemPO;
import com.treasure.mall.biz.entity.order.SubOrderPO;
import com.treasure.mall.biz.entity.pay.PaymentBillPO;
import com.treasure.mall.biz.remote.quickpay.dto.WxTradeOrderDTO;
import com.treasure.mall.biz.service.core.BaseConfigService;
import com.treasure.mall.biz.service.core.auction.AuctionSessionService;
import com.treasure.mall.biz.service.core.order.BizOrderService;
import com.treasure.mall.biz.service.core.order.DealOrderService;
import com.treasure.mall.biz.service.core.pay.PayService;
import com.treasure.mall.biz.service.core.pay.PaymentBillService;
import com.treasure.mall.biz.service.core.product.ProductService;
import com.treasure.mall.biz.service.core.user.MerchantService;
import com.treasure.mall.biz.service.core.user.UserService;
import com.treasure.mall.zbq.common.MathUtils;
import com.treasure.mall.zbq.common.RandomUtils;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.base.CodeDescEnumHelper;
import com.treasure.mall.zbq.common.ienum.log.AdvanceLogType;
import com.treasure.mall.zbq.common.ienum.order.OrderEnums;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * @author allan
 * @version 1.0.0
 * @date 2020/6/13
 */
@Service
@Slf4j
public class PayServiceImpl implements PayService {
    @Resource
    private PaymentBillService paymentBillService;
    @Resource
    private DealOrderService dealOrderService;
    @Resource
    private BizOrderService bizOrderService;
    @Resource
    private UserService userService;
    @Resource
    private ProductService productService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private BaseConfigService baseConfigService;
    @Autowired
    private AuctionSessionService auctionSessionService;
    @Autowired
    private MerchantService merchantService;

    @Override
    public PaymentBillPO createBill(PaymentBillSaveDTO paymentBillSaveDTO) {
        return paymentBillService.save(paymentBillSaveDTO);
    }

    @Override
    public WxTradeOrderDTO pay(String orderId) {
        //得到需要支付的付款单
        PaymentBillPO billPO = paymentBillService.getThirdPayBill(orderId);
        if (billPO == null) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "未找到需要支付的付款单"));
        }
        return this.pay(billPO);
    }

    @Override
    public WxTradeOrderDTO pay(PaymentBillPO billPO) {
        if (billPO.getPayStatus() == OrderEnums.PayStatus.PAYED) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "该付款单已经支付"));
        }
        switch (billPO.getPayType()) {
            case WECHAT_PAY:
            case WECHAT_PAY_ANDROID:
            case WECHAT_PAY_IOS:
                WxTradeOrderDTO tradeOrderDTO = new WxTradeOrderDTO();
                tradeOrderDTO.setOrderId(billPO.getId());
                tradeOrderDTO.setOpenId(billPO.getPayer().getWechatUser().getOpenId());
                tradeOrderDTO.setOrderName(billPO.getId());
                tradeOrderDTO.setSurplusAmount(billPO.getAmount());
                tradeOrderDTO.setAppId(billPO.getPayer().getWechatUser().getAppId());
                return tradeOrderDTO;
            default:
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "不支持的支付方式"));
        }
    }

    @Override
    public WxTradeOrderDTO pay(PayDTO payDTO) {
        PaymentBillSaveDTO dto = new PaymentBillSaveDTO();
        dto.setUserId(payDTO.getUserPO().getUserId());
        dto.setDealType(CodeDescEnumHelper.getEnumTypeByCode(OrderEnums.DealType.class, payDTO.getDealType()));
        switch (dto.getDealType()) {
            case UPGRADE:
                BasicsConfig basicsConfig = baseConfigService.getConfig().getBasicsConfig();
                dto.setAmount(basicsConfig.getUpgradeAmount());
                break;
            case AUCTION:
                //拍卖的
                dto.setAmount(payDTO.getAmount());
                dto.setAuctionSessionId(payDTO.getSessionId());
                break;
            case DEPOSIT_RECHARGE:
            case MEMBER:
            case PARTNER:
                dto.setAmount(payDTO.getAmount());
                break;
            default:
                throw new ApiException(ApiResult.errorWith(ResultCodeEnum.BIZ_ERROR, "不支持的销售类型"));
        }
        dto.setPayType(CodeDescEnumHelper.getEnumTypeByCode(OrderEnums.PayType.class, payDTO.getPayType()));
        dto.setOpenId(payDTO.getUserPO().getWechatUser().getOpenId());
        dto.setOrderId(RandomUtils.randomFlowNo());
        dto.setThirdPay(true);

        PaymentBillPO po = createBill(dto);
        return pay(po);
    }

    @Override
    public WxTradeOrderDTO pay(DealOrderPO orderPO) {
        //生成付款单
        PaymentBillSaveDTO paymentBillSaveDTO = new PaymentBillSaveDTO(OrderEnums.DealType.ORDER, orderPO);
        PaymentBillPO thirdPay = null;
        if (MathUtils.greater(orderPO.getBalance(), BigDecimal.ZERO)) {
            //查看是否已经有支付单
            PaymentBillPO balancePay = paymentBillService.getBalancePayBill(orderPO.getOrderId());
            if (balancePay == null) {
                //生成余额支付付款单
                paymentBillSaveDTO.setPayType(OrderEnums.PayType.BALANCE_PAY);
                paymentBillSaveDTO.setThirdPay(false);
                paymentBillSaveDTO.setAmount(orderPO.getBalance());

                createBill(paymentBillSaveDTO);
            } else {
                balancePay.setAmount(orderPO.getBalance());
            }
        }
        if (MathUtils.greater(orderPO.getSurplusAmount(), BigDecimal.ZERO)) {
            thirdPay = paymentBillService.getThirdPayBill(orderPO.getOrderId());
            if (thirdPay == null) {
                //生成第三方支付的订单
                paymentBillSaveDTO.setPayType(OrderEnums.PayType.WECHAT_PAY);
                paymentBillSaveDTO.setAmount(orderPO.getSurplusAmount());
                paymentBillSaveDTO.setThirdPay(true);

                thirdPay = createBill(paymentBillSaveDTO);
            } else {
                thirdPay.setAmount(orderPO.getSurplusAmount());
            }
        }

        if (thirdPay == null) {
            //直接回调
            threadPoolTaskExecutor.execute(() -> payed(orderPO.getOrderId(), OrderEnums.PayStatus.PAYED));
            return null;
        } else {
            //第三方支付
            return pay(thirdPay);
        }
    }

    @Override
    public void thirdPayed(String paymentBillId, String thirdTradingNo, boolean isSuccess, String resultDesc) {
        PaymentBillPO paymentBillPO = paymentBillService.findById(paymentBillId);
        if (paymentBillPO.getPayStatus() == OrderEnums.PayStatus.PAYED) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "付款单已支付"));
        }
        paymentBillPO.setThirdTradingNo(thirdTradingNo);
        paymentBillPO.setPayStatus(isSuccess ? OrderEnums.PayStatus.PAYED : OrderEnums.PayStatus.FAILED);
        paymentBillPO.setResultDesc(resultDesc);


        if (paymentBillPO.getDealType() == OrderEnums.DealType.ORDER) {
            paymentBillService.save(paymentBillPO);
            //销售订单，得到其他付款单
            payed(paymentBillPO.getOrderId(), paymentBillPO.getPayStatus());
        } else {
            if (isSuccess) {
                BizOrderCreateDTO orderCreateDTO = new BizOrderCreateDTO();
                orderCreateDTO.setFinalAmount(paymentBillPO.getAmount());
                orderCreateDTO.setDealType(paymentBillPO.getDealType());
                orderCreateDTO.setPaymentBillPO(paymentBillPO);
                orderCreateDTO.setPayType(paymentBillPO.getPayType());
                orderCreateDTO.setUserId(paymentBillPO.getPayer().getUserId());
                orderCreateDTO.setSessionId(paymentBillPO.getAuctionSessionId());
                BizOrderPO bizOrderPO = bizOrderService.create(orderCreateDTO);
                paymentBillPO.setOrderId(bizOrderPO.getOrderId());
                paymentBillService.save(paymentBillPO);
            }
        }
    }

    @Override
    public void payed(String orderId, OrderEnums.PayStatus payStatus) {
        List<PaymentBillPO> paymentBillPOS = paymentBillService.getUserPayBill(orderId);
        for (PaymentBillPO billPO : paymentBillPOS) {
            billPO.setPayStatus(payStatus);
            paymentBillService.save(billPO);

            //如果支付成功，余额支付的扣除用户可用余额
            if (payStatus == OrderEnums.PayStatus.PAYED) {
                if (billPO.getPayType() == OrderEnums.PayType.BALANCE_PAY) {

                    //释放锁定余额
                    userService.modifyLockBalance(billPO.getPayer().getUserId(), billPO.getAmount().negate());
                    ModifyBalanceDTO modifyBalanceDTO = new ModifyBalanceDTO();
                    modifyBalanceDTO.setOrderId(billPO.getId());
                    try {
                        DealOrderPO dealOrderPO = dealOrderService.findById(orderId);
                        if (dealOrderPO != null && dealOrderPO.getSubOrderPOS().size() > 0) {
                            modifyBalanceDTO.setOrderId(dealOrderPO.getSubOrderPOS().get(0).getSubOrderId());
                        }
                    } catch (Exception e) {

                    }

                    modifyBalanceDTO.setAmount(billPO.getAmount().negate());
                    modifyBalanceDTO.setId(billPO.getPayer().getUserId());
                    modifyBalanceDTO.setLogType(AdvanceLogType.ORDER_PAY);
                    //扣除用户可用余额
                    userService.modifyBalance(modifyBalanceDTO);

                }
            }
        }

        //订单支付完成
        if (payStatus == OrderEnums.PayStatus.PAYED) {
            dealOrderService.orderPayed(orderId);
        }
    }

    @Override
    public void payTimeout(String orderId) {
        //修改订单状态
        DealOrderPO dealOrderPO = dealOrderService.findById(orderId);
        if (dealOrderPO.getPayStatus() == OrderEnums.PayStatus.PAYED) {
            return;
        }
        //如果不是待付款情况下，直接结束，只有待付款情况下，才能执行超时后续业务流程
        if (dealOrderPO.getPayStatus() != OrderEnums.PayStatus.TO_PAY) {
            return;
        }


        dealOrderPO.setPayStatus(OrderEnums.PayStatus.TIME_OUT);
        dealOrderPO.getSubOrderPOS().forEach(p -> {
            p.setStatus(OrderEnums.Status.CLOSED);
            for (OrderItemPO orderItemPO : p.getOrderItemPOS()) {
                //减掉锁定的库存
                productService.updateStores(orderItemPO.getGoodsInfo().getGoodsId(), 0, orderItemPO.getNum() * -1);
            }
        });

        //释放锁定余额
        if (dealOrderPO.getBalance() != null && MathUtils.greater(dealOrderPO.getBalance(), BigDecimal.ZERO)) {
            userService.modifyLockBalance(dealOrderPO.getUserPO().getUserId(), dealOrderPO.getBalance().negate());
        }


        dealOrderService.save(dealOrderPO);

        //修改付款单状态
        List<PaymentBillPO> paymentBillPOS = paymentBillService.findByOrder(orderId);
        paymentBillPOS.forEach(p -> p.setPayStatus(OrderEnums.PayStatus.TIME_OUT));

        paymentBillService.saveAll(paymentBillPOS);

        SubOrderPO subOrderPO = dealOrderPO.getSubOrderPOS().get(0);
        //如果是拍卖的，违约了，这个保证金要加到商家上
        if (subOrderPO.getOrderType() == OrderEnums.OrderType.AUCTION) {
            BizOrderPO bizOrderPO = bizOrderService.findByAuctionAndUser(dealOrderPO.getUserPO().getUserId(), subOrderPO.getAuctionSessionId());
            if (bizOrderPO != null) {
                //如果是直播间的，则取直播间设置的抽佣比例
                BigDecimal serviceRate = subOrderPO.getOrderItemPOS().get(0).getGoodsInfo().getServiceRate();
                BigDecimal payment = serviceRate
                        .multiply(bizOrderPO.getFinalAmount())
                        .divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP);

                //给到商家可用货款
                ModifyBalanceDTO modifyBalanceDTO = new ModifyBalanceDTO();
                modifyBalanceDTO.setAmount(payment);
                modifyBalanceDTO.setOrderId(subOrderPO.getSubOrderId());
                modifyBalanceDTO.setLogType(AdvanceLogType.LOG_TYPE17);
                modifyBalanceDTO.setId(subOrderPO.getMerchantPO().getMerchantId());
                merchantService.modifyBalance(modifyBalanceDTO);
            }
        }
    }
}
